package com.zms.maze;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Stroke;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

import javax.imageio.ImageIO;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;

public class MazeLabel extends JLabel implements MouseListener,ActionListener,MouseMotionListener{
	private static final long serialVersionUID = 1L;
	private static BufferedImage man;
	private static BufferedImage door;
	private static BufferedImage white;
	private static BufferedImage red;
	private static BufferedImage scorpion;
	private static BufferedImage trap;
	private static BufferedImage key;
	static {
		try {
			man=ImageIO.read(MazeLabel.class.getClassLoader().getResource("man.gif"));
			door=ImageIO.read(MazeLabel.class.getClassLoader().getResource("door.gif"));
			white=ImageIO.read(MazeLabel.class.getClassLoader().getResource("white.gif"));
			red=ImageIO.read(MazeLabel.class.getClassLoader().getResource("red.gif"));
			scorpion=ImageIO.read(MazeLabel.class.getClassLoader().getResource("scorpion.gif"));
			trap=ImageIO.read(MazeLabel.class.getClassLoader().getResource("trap.gif"));
			key=ImageIO.read(MazeLabel.class.getClassLoader().getResource("key.gif"));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}	
	private int processPoint(Point p) {
		int nx=(int)Math.round(p.x*1.0/Maze.BlockWidth);
		int ny=(int)Math.round(p.y*1.0/Maze.BlockHeight);
		if(Math.abs(nx*Maze.BlockWidth-p.x)<8 && Math.abs(ny*Maze.BlockHeight-p.y)<8 && nx>0 && ny>0) {
			p.x=nx;
			p.y=ny;
			return 0;
		}
		if(Math.abs(nx*Maze.BlockWidth-p.x)>15 && Math.abs(ny*Maze.BlockHeight-p.y)>15) {
			if(p.x<nx*Maze.BlockWidth) {
				nx--;
			}
			if(p.y<ny*Maze.BlockHeight) {
				ny--;
			}
			if(nx>=0 && ny>=0) {
				p.x=nx;
				p.y=ny;
				return 1;
			}
		}
		return 2;
	}
	public void mouseClicked(MouseEvent e) {
		if(e.getButton()==MouseEvent.BUTTON1 && e.getClickCount()==2) {
			Point p=e.getPoint();
			int n=processPoint(p);
			if(n==0) {
				maze.blockcolumns=p.x-1;
				maze.blockrows=p.y-1;
				this.repaint();
			}
		}
		if (e.getButton()==MouseEvent.BUTTON1 && e.getClickCount()==1)
		{
			maze.manx+=2;
			maze.many+=2;
			this.repaint();
		}
	}
	public void mouseEntered(MouseEvent e) {		
	}
	public void mouseExited(MouseEvent e) {
	}
	private JPopupMenu menu=new JPopupMenu();
	{
		JMenuItem manitem=new JMenuItem("Man");
		JMenuItem dooritem=new JMenuItem("Door");
		JMenuItem whitemummy=new JMenuItem("White Mummy");
		JMenuItem redmummy=new JMenuItem("Red Mummy");
		JMenuItem scorpion=new JMenuItem("Scorpion");
		JMenuItem trap=new JMenuItem("Trap");
		JMenuItem save=new JMenuItem("Save");
		JMenuItem clear=new JMenuItem("Clear");
		JMenuItem key=new JMenuItem("Key");
		menu.add(manitem);
		menu.add(dooritem);		
		menu.add(whitemummy);
		menu.add(redmummy);
		menu.add(scorpion);
		menu.add(trap);
		menu.add(key);
		menu.addSeparator();
		menu.add(save);
		menu.add(clear);
		manitem.setActionCommand("man");
		manitem.addActionListener(this);
		dooritem.setActionCommand("door");
		dooritem.addActionListener(this);
		whitemummy.setActionCommand("white");
		whitemummy.addActionListener(this);
		redmummy.setActionCommand("red");
		redmummy.addActionListener(this);
		scorpion.setActionCommand("scorpion");
		scorpion.addActionListener(this);
		trap.setActionCommand("trap");
		trap.addActionListener(this);
		save.setActionCommand("save");
		save.addActionListener(this);
		clear.setActionCommand("clear");
		clear.addActionListener(this);
		key.setActionCommand("key");
		key.addActionListener(this);
	}	
	
	public void mousePressed(MouseEvent e) {
		okpress=false;
		pressp=e.getPoint();
		if(e.getButton()==MouseEvent.BUTTON1 && processPoint(pressp)==0) {
			okpress=true;
			pressp.x*=Maze.BlockWidth;
			pressp.y*=Maze.BlockHeight;
			lastp=null;
			hasdrag=false;
		}
	}
	private Point rightpoint;
	private Line lastline=null;
	public void mouseReleased(MouseEvent e) {
		if(e.isPopupTrigger()) {
			this.rightpoint=e.getPoint();
			menu.show(e.getComponent(),rightpoint.x,rightpoint.y);
		}
		if(okpress && hasdrag && e.getButton()==MouseEvent.BUTTON1) {
			Graphics2D g=(Graphics2D)this.getGraphics();
			g.setStroke(stroke);
			g.setXORMode(Color.ORANGE);
			g.drawLine(pressp.x,pressp.y,lastp.x,lastp.y);
			Point p=e.getPoint();
			if(processPoint(p)==0) {
				processPoint(pressp);
				Line line=new Line(pressp.x-1,pressp.y-1,p.x-1,p.y-1);
				lastline=line;
				maze.lines.add(line);
				maze.validLines();
				this.repaint();
			}
			okpress=false;
		}
	}
	public MazeLabel() {
		this.addMouseListener(this);
		this.addMouseMotionListener(this);
	}
	//trung phan modified on 17/09/12_Begin
	//get maze from file to get visually maze
	public Maze getMazeFromFile()
	{
		try {
			File parent=new File("C:\\Users\\Phan Quang Trung\\workspace\\MummyMaze\\bin\\data");
			File[] files=parent.listFiles();
			int n=0;
			File file=files[1];
			System.out.println(++n);
			System.out.println(file);
			ObjectInputStream input=new ObjectInputStream(new FileInputStream(file));
			Maze maze=Maze.readObject(input);
			input.close();				
			ObjectOutputStream output=new ObjectOutputStream(new FileOutputStream(file));
			maze.writeObject(output);
			output.close();
			return maze;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
					
		}
	}
	
//Comment the below method.
	private Maze maze=new Maze();
	{
		maze.manx=-1;
		maze.many=-1;
		maze.doorx=-2;
		maze.doory=-2;
	}
     	public void paint(Graphics g) {
		if(maze.blockcolumns<1) {
			maze.blockcolumns=10;
		}
		if(maze.blockrows<1) {
			maze.blockrows=10;
		}
		g.setColor(Color.GRAY);
		g.fillRect(0,0,(maze.blockcolumns+2)*Maze.BlockWidth,(maze.blockrows+2)*Maze.BlockHeight);
		g.setColor(Color.DARK_GRAY);
		g.fillRect(Maze.BlockWidth,Maze.BlockHeight,maze.blockcolumns*Maze.BlockWidth,maze.blockrows*Maze.BlockHeight);
		g.setColor(Color.RED);
		for(int i=0;i<=(maze.blockcolumns+2);i++) {
			for(int j=0;j<=(maze.blockrows+2);j++) {
				int x=i*Maze.BlockWidth;
				int y=j*Maze.BlockHeight;
				int r=5;
				g.fillOval(x-r,y-r,2*r,2*r);
			}
		}
		if(maze.manx>=0 && maze.many>=0) {
			g.drawImage(man,(maze.manx+1)*Maze.BlockWidth+10,(maze.many+1)*Maze.BlockHeight+10,Maze.BlockWidth-20,Maze.BlockHeight-20,this);
		}
		if(maze.doorx>=-1 && maze.doory>=-1) {
			g.drawImage(door,(maze.doorx+1)*Maze.BlockWidth+10,(maze.doory+1)*Maze.BlockHeight+10,Maze.BlockWidth-20,Maze.BlockHeight-20,this);
		}
		for(Mummy mummy:maze.mummies) {
			BufferedImage image;
			if(mummy.type==MummyType.White) {
				image=white;
			} else {
				image=red;
			}
			g.drawImage(image,(mummy.x+1)*Maze.BlockWidth+10,(mummy.y+1)*Maze.BlockHeight+10,Maze.BlockWidth-20,Maze.BlockHeight-20,this);
		}
		for(Scorpion ascorpion:maze.scorpions) {
			g.drawImage(scorpion,(ascorpion.x+1)*Maze.BlockWidth+10,(ascorpion.y+1)*Maze.BlockHeight+10,Maze.BlockWidth-20,Maze.BlockHeight-20,this);
		}
		for(Trap atrap:maze.traps) {
			g.drawImage(trap,(atrap.startx+1)*Maze.BlockWidth+10,(atrap.starty+1)*Maze.BlockHeight+10,Maze.BlockWidth-20,Maze.BlockHeight-20,this);
		}
		Graphics2D g2d=(Graphics2D)g;
		g2d.setStroke(stroke);
		g2d.setColor(Color.GREEN);
		for(Line line:maze.lines) {			
			g2d.drawLine(Maze.BlockWidth*(line.x1+1),Maze.BlockHeight*(line.y1+1),Maze.BlockWidth*(line.x2+1),Maze.BlockHeight*(line.y2+1));
		}
		if(maze.toggles.size()>0) {
			g2d.setColor(Color.PINK);
		}
		for(ToggleLine line:maze.toggles) {
			g2d.drawLine(Maze.BlockWidth*(line.x1+1),Maze.BlockHeight*(line.y1+1),Maze.BlockWidth*(line.x2+1),Maze.BlockHeight*(line.y2+1));
			g.drawImage(key,(line.togglex+1)*Maze.BlockWidth+(Maze.BlockWidth-Maze.KeyWidth)/2,(line.toggley+1)*Maze.BlockHeight+(Maze.BlockWidth-Maze.KeyHeight)/2,Maze.BlockWidth-20,Maze.BlockHeight-20,this);
		}
	}
	private void removeObject() {
		Object obj=null;
		for(Mummy mummy:maze.mummies) {
			if(mummy.x==rightpoint.x && mummy.y==rightpoint.y) {
				obj=mummy;
			}
		}		
		for(Scorpion ascorpion:maze.scorpions) {
			if(ascorpion.x==rightpoint.x && ascorpion.y==rightpoint.y) {
				obj=ascorpion;
			}
		}
		for(Trap atrap:maze.traps) {
			if(atrap.startx==rightpoint.x && atrap.starty==rightpoint.y) {
				obj=atrap;
			}
		}
		maze.mummies.remove(obj);
		maze.scorpions.remove(obj);
		maze.traps.remove(obj);
	}
	public void actionPerformed(ActionEvent e) {
		String command=e.getActionCommand();
		if("save".equals(command)) {
			this.doSave();
		} else if("clear".equals(command)) {
			this.maze=new Maze();
			maze.manx=maze.many=-1;
			maze.doorx=maze.doory=-2;
			this.repaint();
			lastline=null;
		} else {
			if(processPoint(rightpoint)!=1) {
				return;
			}			
			if("man".equals(command)) {
				maze.manx=rightpoint.x-1;
				maze.many=rightpoint.y-1;
					
			} else if("door".equals(command)) {
				maze.doorx=rightpoint.x-1;
				maze.doory=rightpoint.y-1;
			} else if("white".equals(command)) {
				this.removeObject();
				maze.mummies.add(new Mummy(rightpoint.x-1,rightpoint.y-1,MummyType.White));
			} else if("red".equals(command)) {
				this.removeObject();
				maze.mummies.add(new Mummy(rightpoint.x-1,rightpoint.y-1,MummyType.Red));
			} else if("scorpion".equals(command)) {
				this.removeObject();
				maze.scorpions.add(new Scorpion(rightpoint.x-1,rightpoint.y-1));
			} else if("trap".equals(command)) {
				this.removeObject();
				maze.traps.add(new Trap(rightpoint.x-1,rightpoint.y-1));
			} else if("key".equals(command)) {
				if(lastline!=null && maze.lines.contains(lastline)) {
					maze.lines.remove(lastline);
					maze.toggles.add(new ToggleLine(lastline,rightpoint.x-1,rightpoint.y-1,1));
					maze.validLines();
				}
			}
			this.repaint();
		}
	}
	private void doSave() {
		File file=new File("./WebContent/WEB-INF/data");
		if(!file.exists()) {
			file=new File("./data");
		}
		int n=file.list().length;
		file=new File(file,String.valueOf(n+1)+".dat");
		FileOutputStream output=null;
		try {			
			output=new FileOutputStream(file);
			ObjectOutputStream out=new ObjectOutputStream(output);
			maze.writeObject(out);
			out.flush();
			String s="Success saved in file "+file.getName();
			file=new File("./.deployables/maze/WEB-INF/data");
			if(file.exists()) {
				file=new File(file,String.valueOf(n+1)+".dat");
				output=new FileOutputStream(file);				
				out=new ObjectOutputStream(output);
				maze.writeObject(out);
				out.flush();
			}
			JOptionPane.showMessageDialog(MazeCreator.frame,s,"Info",JOptionPane.INFORMATION_MESSAGE);
		} catch (Exception e) {			
			JOptionPane.showMessageDialog(MazeCreator.frame,e.getMessage(),"Error",JOptionPane.ERROR_MESSAGE);
		} finally {			
			if(output!=null) {
				try {
					output.close();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	}
	private boolean okpress;
	private Point pressp;
	private Point lastp;
	private boolean hasdrag;
	private Stroke stroke=new BasicStroke(5f);
	public void mouseDragged(MouseEvent e) {
		if(okpress) {
			hasdrag=true;
			Point p=e.getPoint();
			Graphics2D g=(Graphics2D)this.getGraphics();
			g.setStroke(stroke);
			g.setXORMode(Color.ORANGE);
			if(lastp!=null) {				
				g.drawLine(pressp.x,pressp.y,lastp.x,lastp.y);
			}
			g.drawLine(pressp.x,pressp.y,p.x,p.y);
			lastp=p;
		}
	}
	public void mouseMoved(MouseEvent e) {		
	}
}
